package com.mf.controller;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.mf.basic.BasicDuration;
import com.mf.basic.BasicKey;
import com.mf.entity.request.AdminUpdateUserPwd;
import com.mf.entity.request.UserRequest;
import com.mf.entity.request.UserUpdatePwd;
import com.mf.entity.request.serach.UserSearchRequest;
import com.mf.entity.security.vo.UserByRoleVo;
import com.mf.service.IUserService;
import io.github.heollhai.common.config.exceptions.GraceException;
import io.github.heollhai.common.config.reids.RedisOperator;
import io.github.heollhai.common.config.security.utils.SecurityUtils;
import io.github.heollhai.common.entity.bo.UserBo;
import io.github.heollhai.common.entity.request.publicRequest.PublicUpdateStatusRequest;
import io.github.heollhai.common.entity.security.dto.UserByRoleDto;
import io.github.heollhai.common.entity.vo.user.LoginResultVo;
import io.github.heollhai.common.entity.vo.user.UserVo;
import io.github.heollhai.common.enums.EnableOrDisableEnum;
import io.github.heollhai.common.result.Result;
import io.github.heollhai.common.result.ResultCodeEnum;
import io.github.heollhai.common.utils.HttpServletRequestUtils;
import io.github.heollhai.common.utils.JWTUtil;
import io.github.heollhai.common.utils.VerifyUtils;
import io.github.heollhai.common.utils.enums.EnumUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;

import static io.github.heollhai.common.result.ResultCodeEnum.LOGIN_EXPIRED;


/**
 * 用户表
 *
 * @author mf
 * @since 2024-08-06
 */
@RestController
@RequestMapping("/auth/user/v1")
@Tag(name = "用户管理")
@Slf4j
public class UserController {

    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private IUserService userService;

    @Resource
    private RedisOperator redisOperator;

    @Operation(summary = "登录")
    @PostMapping("login")
    public Result<String> login(@RequestParam("username") String username, @RequestParam("password") String password) {
        System.out.println("接口会直接走security登录，，这个只是为了让文档上有登录接口,后续会修改到对应的security中");
        return Result.success(null);
    }

    @Operation(summary = "用户新增|编辑")
    @PostMapping("register")
    public Result<Integer> register(@Valid @RequestBody UserRequest userRequest) {

        UserBo userBo = new UserBo();
        BeanUtils.copyProperties(userRequest, userBo);

        if (VerifyUtils.isEmpty(userBo.getId())) {
            // 默认密码 账号 + !!!
            userBo.setPassword(passwordEncoder.encode(userRequest.getAccount() + "!!!"));
        } else {
            userBo.setPassword(null);
        }

        return Result.success(userService.register(userBo));
    }


    @Operation(summary = "删除用户")
    @GetMapping("deleteById")
    public Result<Boolean> deleteById(@RequestParam("id") Integer id) {
        return Result.success(userService.removeById(id));
    }

    @Operation(summary = "管理员修改密码")
    @PostMapping("adminChangeUserByPwd")
    public Result<Boolean> adminChangeUserByPwd(@Valid @RequestBody AdminUpdateUserPwd adminUpdateUserPwd) {
        return changeUserPwd(adminUpdateUserPwd.getAccount(), adminUpdateUserPwd.getPassword());
    }

    /**
     * 根据账号修改密码
     */
    private Result<Boolean> changeUserPwd(String account, String pwd) {
        UserBo userBo = userService.findByAccount(account);
        if (VerifyUtils.isEmpty(userBo)) {
            GraceException.display("用户不存在");
            return null;
        }
        userBo.setPassword(passwordEncoder.encode(pwd));
        redisOperator.delete(BasicKey.REDIS_USER_TOKEN + userBo.getNameAndId());
        return Result.success(userService.updateById(userBo));
    }

    @Operation(summary = "用户修改密码")
    @PostMapping("userChangePwd")
    public Result<Boolean> userChangePwd(@Valid @RequestBody UserUpdatePwd userUpdatePwd) {
        UserByRoleDto userByRoleDto = SecurityUtils.getUserByRoleDto();
        if (VerifyUtils.isEmpty(userByRoleDto)) {
            return null;
        }

        // 验证旧密码是否正确
        if (!passwordEncoder.matches(userUpdatePwd.getOldPassword(), userByRoleDto.getPassword())) {
            GraceException.display("旧密码错误");
            return null;
        }
        return changeUserPwd(userUpdatePwd.getAccount(), userUpdatePwd.getPassword());
    }


    @Operation(summary = "分页查询所有用户")
    @PostMapping("pageListUser")
    public Result<Page<UserVo>> pageListUser(@RequestBody UserSearchRequest userSearchRequest) {
        return Result.success(userService.pageList(userSearchRequest));
    }

    @Operation(summary = "分页查询用户和对应角色")
    @PostMapping("pageListUserAndRole")
    public Result<Page<UserVo>> pageListUserAndRole(@RequestBody UserSearchRequest userSearchRequest) {
        return Result.success(userService.pageListUserAndRole(userSearchRequest));
    }

    @Operation(summary = "获取用户权限")
    @GetMapping("getAuthByUser")
    public Result<UserByRoleVo> getUserAuth(HttpServletRequest request) {
        String token = request.getHeader(BasicKey.HEADER_TOKEN);
        String _token = JWTUtil.checkJwt(token);
        String browserInfo = HttpServletRequestUtils.getBrowserInfo(request, BasicKey.REDIS_USER_TOKEN);
        // 判断token是否过期
        if (VerifyUtils.isNotEmpty(_token) && redisOperator.keyIsExist(browserInfo + _token)) {
            UserByRoleDto userByRoleDto = redisOperator.get(BasicKey.REDIS_USER_TOKEN + _token, UserByRoleDto.class);

            UserVo userVo = new UserVo();
            BeanUtils.copyProperties(userByRoleDto.getUserBo(), userVo);

            UserByRoleVo userByRoleVo = new UserByRoleVo();
            userByRoleVo.setUserVo(userVo);
            userByRoleVo.setRoleList(userByRoleDto.getRoleList());
            userByRoleVo.setFrontRoutes(userByRoleDto.getFrontRoutes());
            userByRoleVo.setButtonPermissionList(userByRoleDto.getButtonPermissionList());
            return Result.success(userByRoleVo);
        }
        return Result.fail(LOGIN_EXPIRED);
    }

    @Operation(summary = "启用|禁用账号")
    @PostMapping("updateStatus")
    public Result<Boolean> updateStatus(@Valid @RequestBody PublicUpdateStatusRequest<Integer> updateStatusRequest) {

        if (EnumUtils.existsInEnum(EnableOrDisableEnum.class, updateStatusRequest.getStatus())) {
            GraceException.display(ResultCodeEnum.STATUS_EXCEPTION);
        }
        UserBo userBo = new UserBo();
        BeanUtils.copyProperties(updateStatusRequest, userBo);
        return Result.success(userService.updateById(userBo));
    }

    @Operation(summary = "通过刷新token更新token时间")
    @PostMapping("updateTokenTime")
    public Result<String> updateTokenTime(@RequestBody() LoginResultVo loginResultVo, HttpServletRequest request) {
        // 前端传入token
        String intToken = request.getHeader(BasicKey.HEADER_TOKEN);
        if (VerifyUtils.isEmpty(intToken)) {
            GraceException.display(ResultCodeEnum.REFRESH_TOKEN_EXPIRED);
        }

        String userIdByName = JWTUtil.checkJwt(intToken);
        if (VerifyUtils.isEmpty(userIdByName)) {
            GraceException.display(ResultCodeEnum.REFRESH_TOKEN_EXPIRED);
        }

        // 获取ip
        String refreshInfo = HttpServletRequestUtils.getBrowserInfo(request, BasicKey.REDIS_USER_REFRESH_TOKEN);
        String tokenInfo = HttpServletRequestUtils.getBrowserInfo(request, BasicKey.REDIS_USER_TOKEN);

        // 获取刷新token 并获取里面的用户信息
        String tokenAndAccount = redisOperator.get(refreshInfo + userIdByName);
        if (VerifyUtils.isEmpty(tokenAndAccount)) {
            return Result.fail(ResultCodeEnum.REFRESH_TOKEN_EXPIRED);
        }
        final String[] split = tokenAndAccount.split("&&");
        String originToken = split[0];

        if (!originToken.equals(intToken)) {
            return Result.fail(ResultCodeEnum.REFRESH_TOKEN_EXPIRED);
        }

        String account = split[1];
        // 获取实时用户信息
        final UserByRoleDto userByRoleDto = (UserByRoleDto) userService.loadUserByUsername(account);

        // 判断刷新token是否过期
        if (VerifyUtils.isEmpty(userByRoleDto)) {
            return Result.fail(ResultCodeEnum.REFRESH_TOKEN_EXPIRED);
        }

        // 存入公共的用户登录信息到 redis
        redisOperator.set(BasicKey.REDIS_USER_TOKEN + userByRoleDto.getNameAndId(),
                JSON.toJSONString(userByRoleDto), BasicDuration.TOKEN_DURATION);

        // 存入用户登录信息到 redis
        redisOperator.set(tokenInfo + userByRoleDto.getNameAndId(), BasicKey.DEFAULT_VALUE,
                BasicDuration.TOKEN_DURATION);

        // 更新刷新token
        redisOperator.set(refreshInfo + userByRoleDto.getNameAndId(),
                originToken + "&&" + userByRoleDto.getUserBo().getAccount(),
                BasicDuration.REFRESH_TOKEN_DURATION);

        return Result.success();
    }
}
